/*
 * stn_libssh_shorts.h
 *
 *  Created on: Jun 27, 2013
 *      Author: alexandru
 *      TO BE COMPILED WITH -lssh from http://www.libssh.org/
 *
 */

#ifndef STN_LIBSSH_SHORTS_H_
#define STN_LIBSSH_SHORTS_H_

#include <iostream>
#include <errno.h>
#include <string>
#include <libssh/libssh.h>
#include <libssh/sftp.h>
#include <sys/stat.h>
#include <fcntl.h>

void stn_connectToRemoteServer(char *REMOTE_HOST, char *password, int verbosity, int port, void (*toDoAfterConnect)(ssh_session session));
int verify_knownhost(ssh_session session);
int scp_connectToWrite(ssh_session session, char *location, void (*toDoAfterConnect)(ssh_session session, ssh_scp scp));

int verify_knownhost(ssh_session session)
{
  int state, hlen;
  unsigned char *hash = NULL;
  char *hexa;
  char buf[10];
  state = ssh_is_server_known(session);
  hlen = ssh_get_pubkey_hash(session, &hash);
  if (hlen < 0)
    return -1;
  switch (state)
  {
    case SSH_SERVER_KNOWN_OK:
      break; /* ok */
    case SSH_SERVER_KNOWN_CHANGED:
      fprintf(stderr, "Host key for server changed: it is now:\n");
      ssh_print_hexa("Public key hash", hash, hlen);
      fprintf(stderr, "For security reasons, connection will be stopped\n");
      free(hash);
      return -1;
    case SSH_SERVER_FOUND_OTHER:
      fprintf(stderr, "The host key for this server was not found but an other"
        "type of key exists.\n");
      fprintf(stderr, "An attacker might change the default server key to"
        "confuse your client into thinking the key does not exist\n");
      free(hash);
      return -1;
    case SSH_SERVER_FILE_NOT_FOUND:
      fprintf(stderr, "Could not find known host file.\n");
      fprintf(stderr, "If you accept the host key here, the file will be"
       "automatically created.\n");
      /* fallback to SSH_SERVER_NOT_KNOWN behavior */
    case SSH_SERVER_NOT_KNOWN:
      hexa = ssh_get_hexa(hash, hlen);
      fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
      fprintf(stderr, "Public key hash: %s\n", hexa);
      free(hexa);
      if (fgets(buf, sizeof(buf), stdin) == NULL)
      {
        free(hash);
        return -1;
      }
      if (strncasecmp(buf, "yes", 3) != 0)
      {
        free(hash);
        return -1;
      }
      if (ssh_write_knownhost(session) < 0)
      {
        fprintf(stderr, "Error %s\n", strerror(errno));
        free(hash);
        return -1;
      }
      break;
    case SSH_SERVER_ERROR:
      fprintf(stderr, "Error %s", ssh_get_error(session));
      free(hash);
      return -1;
  }
  free(hash);
  return 0;
}



void stn_connectToRemoteServer(char *REMOTE_HOST, char *password, int verbosity, int port, void (*toDoAfterConnect)(ssh_session session)){
	ssh_session my_ssh_session = ssh_new();
	int rc;

	if (my_ssh_session == NULL){
		    exit(-1);
		  }else{
			  printf("session created \n");
			  ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, REMOTE_HOST);
			  ssh_options_set(my_ssh_session,SSH_OPTIONS_LOG_VERBOSITY,&verbosity);
			  ssh_options_set(my_ssh_session,SSH_OPTIONS_PORT,&port);
			  ssh_options_set(my_ssh_session,SSH_OPTIONS_USER,"root");

			  //basic conexion:
			  //se face conexiunea:
			  rc = ssh_connect(my_ssh_session);
			  //daca nu e conexiune, inchide
			  if (rc != SSH_OK){
				  fprintf(stderr, "Error connecting to %s: %s\n",REMOTE_HOST, ssh_get_error(my_ssh_session));
			      exit(-1);
			    }else{
			    	 printf("connection done \n");
			    }


			  // Verify the server's identity
			    if (verify_knownhost(my_ssh_session) < 0)
			    {
			      ssh_disconnect(my_ssh_session);
			      ssh_free(my_ssh_session);
			      exit(-1);
			    }

			   //password authentication
	//		    rc = ssh_userauth_publickey_auto(my_ssh_session, "root", "smartx00x");
	//		      if (rc == SSH_AUTH_ERROR)
	//		      {
	//		         fprintf(stderr, "Authentication failed: %s\n",
	//		           ssh_get_error(my_ssh_session));
	//		         return SSH_AUTH_ERROR;
	//		      }
			    	rc = ssh_userauth_password(my_ssh_session,NULL,password);
			        if ( rc == SSH_AUTH_SUCCESS)
			        {
			            printf("Authenticated correctly \n");
			        }

			        toDoAfterConnect(my_ssh_session);

			        printf("statement finished, ssh disconnect ......... \n");

			  ssh_disconnect(my_ssh_session);
		  }

		  ssh_free(my_ssh_session);






}






int scp_create_dir_and_file(ssh_session session, ssh_scp scp, char *dirname, char *fileName, char *content)
{
  int rc;
  int length = strlen(content);

  rc = ssh_scp_push_directory(scp, dirname, S_IRWXU);
  if (rc != SSH_OK)
  {
    fprintf(stderr, "Can't create remote directory: %s\n", ssh_get_error(session));
    return rc;
  }


  rc = ssh_scp_push_file(scp, fileName, length, S_IRUSR |  S_IWUSR);
  if (rc != SSH_OK)
  {
    fprintf(stderr, "Can't open remote file: %s\n", ssh_get_error(session));
    return rc;
  }

  rc = ssh_scp_write(scp, content, length);
  if (rc != SSH_OK)
  {
    fprintf(stderr, "Can't write to remote file: %s\n", ssh_get_error(session));
    return rc;
  }
  return SSH_OK;
}






int scp_connectToWrite(ssh_session session, char *location, void (*toDoAfterConnect)(ssh_session session, ssh_scp scp))
{
  ssh_scp scp;
  int rc;

  scp = ssh_scp_new (session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, location);
  if (scp == NULL)
  {
    fprintf(stderr, "Error allocating scp session: %s\n",ssh_get_error(session));
    return SSH_ERROR;
  }
  rc = ssh_scp_init(scp);
  if (rc != SSH_OK)
  {
    fprintf(stderr, "Error initializing scp session: %s\n", ssh_get_error(session));
    ssh_scp_free(scp);
    return rc;
  }


  toDoAfterConnect(session, scp);

  ssh_scp_close(scp);
  ssh_scp_free(scp);
  return SSH_OK;
}









int scp_receiveData(ssh_session session, ssh_scp scp)
{
  int rc;
  int size, mode;
  char *filename, *buffer;
  rc = ssh_scp_pull_request(scp);
  if (rc != SSH_SCP_REQUEST_NEWFILE)
  {
    fprintf(stderr, "Error receiving information about file: %s\n",
            ssh_get_error(session));
    return SSH_ERROR;
  }
  size = ssh_scp_request_get_size(scp);
  filename = strdup(ssh_scp_request_get_filename(scp));
  mode = ssh_scp_request_get_permissions(scp);
  printf("Receiving file %s, size %d, permisssions 0%o\n",
          filename, size, mode);
  free(filename);
  buffer = (char*)malloc(size);
  if (buffer == NULL)
  {
    fprintf(stderr, "Memory allocation error\n");
    return SSH_ERROR;
  }
  ssh_scp_accept_request(scp);
  rc = ssh_scp_read(scp, buffer, size);
  if (rc == SSH_ERROR)
  {
    fprintf(stderr, "Error receiving file data: %s\n",
            ssh_get_error(session));
    free(buffer);
    return rc;
  }
  printf("Done\n");
  write(1, buffer, size);
  free(buffer);
  rc = ssh_scp_pull_request(scp);
  if (rc != SSH_SCP_REQUEST_EOF)
  {
    fprintf(stderr, "Unexpected request: %s\n",
            ssh_get_error(session));
    return SSH_ERROR;
  }
  return SSH_OK;
}




int scp_readFile(ssh_session session, char * location, void (*useData)(ssh_session session, ssh_scp scp))
{
  ssh_scp scp;
  int rc;


  scp = ssh_scp_new(session, SSH_SCP_READ, location);
  if (scp == NULL)
  {
    fprintf(stderr, "Error allocating scp session: %s\n",
            ssh_get_error(session));
    return SSH_ERROR;
  }

  rc = ssh_scp_init(scp);
  if (rc != SSH_OK)
  {
    fprintf(stderr, "Error initializing scp session: %s\n", ssh_get_error(session));
    ssh_scp_free(scp);
    return rc;
  }

  useData(session, scp);

  ssh_scp_close(scp);
  ssh_scp_free(scp);
  return SSH_OK;
}





//UNFINISHED:



//int scp_recv_file(ssh_session in_session,
//                 char * in_remotefile, char * in_localfile)
//{
//  ssh_scp   t_scp = NULL;
//  int       t_rc, t_filesize, t_filemode = -1;
//  char      *t_filename, *t_buffer;
//
//  t_scp = ssh_scp_new
//    (in_session, SSH_SCP_READ | SSH_SCP_RECURSIVE, in_remotefile);
//
//
//  if (t_scp == NULL)
//  {
//    fprintf(stderr, "Error allocating scp session: %s\n",
//            ssh_get_error(in_session));
//    return SSH_ERROR;
//  }
//
//  t_rc = ssh_scp_init(t_scp);
//  if (t_rc != SSH_OK)
//  {
//    fprintf(stderr, "Error initializing scp session: %s\n",
//            ssh_get_error(in_session));
//    ssh_scp_free(t_scp);
//    return t_rc;
//  }
//
//  //create ssh pull a file request
//  t_rc = ssh_scp_pull_request(t_scp);
//  if (t_rc != SSH_SCP_REQUEST_NEWFILE)
//  {
//    fprintf(stderr, "Error receiving information about file: %s\n",
//            ssh_get_error(in_session));
//    return SSH_ERROR;
//  }
//
//  t_filesize = ssh_scp_request_get_size(t_scp);
//  t_filename = strdup(ssh_scp_request_get_filename(t_scp));
//  t_filemode = ssh_scp_request_get_permissions(t_scp);
//
//  printf("Receiving file %s, size %d, permisssions 0%o\n",
//          t_filename, t_filesize, t_filemode);
//
//  t_buffer = (char*) malloc(t_filesize);
//  if (t_buffer == NULL)
//  {
//    fprintf(stderr, "Memory allocation error\n");
//    return SSH_ERROR;
//  }
//
//  ssh_scp_accept_request(t_scp);
//  t_rc = ssh_scp_read(t_scp, t_buffer, t_filesize);
//  if (t_rc == SSH_ERROR)
//  {
//    fprintf(stderr, "Error receiving file data: %s\n",
//            ssh_get_error(in_session));
//    free(t_buffer);
//    return t_rc;
//  }
//  printf("Done\n");
//
//  //write buffer to file
//write(in_localfile, t_buffer, t_filesize);
//
//
//  //free allocated memory
//  free(t_buffer);
//  free(t_filename);
//
//
//  t_rc = ssh_scp_pull_request(t_scp);
//  if (t_rc != SSH_SCP_REQUEST_EOF)
//  {
//    fprintf(stderr, "Unexpected request: %s\n",
//            ssh_get_error(in_session));
//    return SSH_ERROR;
//  }



  //close scp and free
//  ssh_scp_close(t_scp);
//  ssh_scp_free(t_scp);
//  return SSH_OK;
//}








int sftp_helloworld(ssh_session session, sftp_session sftp)
{
  int access_type = O_WRONLY | O_CREAT | O_TRUNC;
  sftp_file file;
  const char *helloworld = "Hello, World!\n";
  int length = strlen(helloworld);
  int rc, nwritten;
//  ...
  file = sftp_open(sftp, "helloworld/helloworld.txt", access_type, S_IRWXU);
  if (file == NULL)
  {
    fprintf(stderr, "Can't open file for writing: %s\n", ssh_get_error(session));
    return SSH_ERROR;
  }
  nwritten = sftp_write(file, helloworld, length);
  if (nwritten != length)
  {
    fprintf(stderr, "Can't write data to file: %s\n", ssh_get_error(session));
    sftp_close(file);
    return SSH_ERROR;
  }
  rc = sftp_close(file);
  if (rc != SSH_OK)
  {
    fprintf(stderr, "Can't close the written file: %s\n", ssh_get_error(session));
    return rc;
  }
  return SSH_OK;
}




int authenticate_password(ssh_session session)
{
  char *password;
  int rc;
  password = getpass("Enter your password: ");
  rc = ssh_userauth_password(session, NULL, password);
  if (rc == SSH_AUTH_ERROR)
  {
     fprintf(stderr, "Authentication failed: %s\n",
       ssh_get_error(session));
     return SSH_AUTH_ERROR;
  }
  return rc;
}


int authenticate_pubkey(ssh_session session)
{
  int rc;
  rc = ssh_userauth_autopubkey(session, NULL);
  if (rc == SSH_AUTH_ERROR)
  {
     fprintf(stderr, "Authentication failed: %s\n",
       ssh_get_error(session));
     return SSH_AUTH_ERROR;
  }
  return rc;
}





#endif /* STN_LIBSSH_SHORTS_H_ */
